import { arrsMethods } from './array.js'
import Dep from './dep.js'
//开启响应式模式
export function observer(data) {
    //判断数据的类型,11,22,'string'
    if (typeof data !== 'object' || data == null) return;
    if (data._ob_) return
    //定义响应式模式
    return new Observer(data)
}
//直接定义类,耦合性比较好
class Observer {
    //构造器,定义实例的方法
    constructor(value) {
        this.dep=new Dep();
        //value._ob_=this;
        //将 this=>当前实例对象,实例对象有observeArray方法,将this赋值给value._ob_
        Object.defineProperty(value, '_ob_', {
            value: this,
            enumerable: false,
            configurable: false
        })


        //判断是否监听的值是不是数组
        if (Array.isArray(value)) {
            //直接改写arr的原型 obj.__proto__ => 改成自己自定义的数组方法
            value.__proto__ ? value.__proto__ = arrsMethods : Object.setPrototypeOf(value, arrsMethods)
            //如果数组中带有对象,将其转成成响应式
            this.observeArray(value)
        } else {
            //将普通对象转化成响应式对象
            this.walker(value);
        }
    }
    //将普通对象转化成响应式对象 
    walker(value) {
        //遍历当前对象的key值=>数组,循环数组
        Object.keys(value).forEach(key => {
            //数据劫持--普通对象=>响应式对象
            defineReactive(value, key, value[key]);
        })
    }

    //如果数组中带有对象,将其转成成响应式
    observeArray(value) {
        for (let i = 0; i < value.length; i++) {
            //调用观察者模式
            observer(value[i])
        }
    }
}
function dependArray(val){
    //循环数组
    for (let i = 0; i < val.length; i++) {
        const current = val[i];
        //调用每个对象_ob_的dep上的depend方法
        current._ob_ && current._ob_.dep.depend();
        //如果current是数组,递归依赖对象收集
        if(Array.isArray(current)) dependArray(current)
    }
}


//将对象转换成响应式对象
export function defineReactive(data, key, val) {
    //Object.defineProperty('代定义的对象','待修改的属性','修改的属性描述符')

    //如果data 返回的对象中又包含一层对象,用递归观察数据----data(){ return { obj:{ a:ob2{} } } }
    let chilOb=observer(val)
    //console.log(chilOb);
    //每次给属性添加一个dep
    let dep = new Dep();
    Object.defineProperty(data, key, {
        //获取属性
        get() {
            //让这个属性自己dep记住这个watcher,也让这个wather记住这个dep
            //debugger
            if (Dep.target) {
                //对象的依赖收集
                dep.depend();
                if(chilOb) {
                    //子对象
                    chilOb.dep.depend()
                    //判断值是否为数组
                    if(Array.isArray(val)){
                        //数组的依赖收集
                        dependArray(val)
                    }
                };
            }
            return val;
        },
        //设置属性
        set(newVal) {
            //console.log(dep);
            //如果新旧值相等 无需操作
            if (newVal === val) return;
            //观察 被修改的对象
            observer(newVal)
            //否则修改
            val = newVal;
            //通知dep中记录的watcher让它执行
            dep.notify();
        }
    })
}
